﻿using System;
using System.ComponentModel;
using System.Drawing.Design;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.Design;

namespace Kyoh.Lib.WinForms
{
    /// <summary><see cref="Encoding"/> クラスのエディタを提供します。</summary>
    public class EncodingEditor : UITypeEditor
    {
        /// <summary><see cref="EncodingEditor"/> クラスの新しいインスタンスを初期化します。</summary>
        public EncodingEditor() { }
        
        /// <summary><see cref="Encoding"/> を選択する画面を表示します。</summary>
        /// <param name="context">追加のコンテキスト情報を取得するために使用できる <see cref="ITypeDescriptorContext"/>。</param>
        /// <param name="provider">このエディタがサービスを取得するために使用できる <see cref="IServiceProvider"/>。</param>
        /// <param name="value">編集対象のオブジェクト。</param>
        /// <returns>オブジェクトの新しい値。オブジェクトの値が変更されていない場合は、このメソッドは渡されたオブジェクトと同じオブジェクトを返します。</returns>
        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            Type propType = null;
            bool valid = false;
            Encoding enc = null;

            if (context != null && context.Instance != null && context.PropertyDescriptor != null && provider != null)
            {
                propType = context.PropertyDescriptor.PropertyType;

                // when the property is directly an enum, this is easy
                if (propType == typeof(Encoding))
                {
                    enc = (Encoding)value;
                    valid = true;
                }
                else if (propType == typeof(string))
                {
                    enc = Encoding.GetEncoding((string)value);
                    valid = true;
                }
            }

            if (valid)
            {
                // リストボックスを表示するためのエディタ画面を取得する。
                IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));

                // リストボックスを作成する
                using (ListBox listBox = new ListBox())
                {
                    // リストボックスに表示するエンコーディングを取得し、追加する。
                    int index = 0;
                    foreach (var encoding in Encoding.GetEncodings())
                    {
                        listBox.Items.Add(encoding);
                        if (enc != null && encoding.CodePage == enc.CodePage)
                            listBox.SelectedIndex = index;
                        index++;
                    }

                    // リストボックスのプロパティ/イベントを設定する。
                    listBox.DisplayMember = "DisplayName";
                    listBox.Sorted = true;
                    // 選択時にポップアップを閉じる。
                    listBox.SelectedIndexChanged += new EventHandler((sender, e) => { edSvc.CloseDropDown(); });

                    // 編集用ポップアップを表示する
                    edSvc.DropDownControl(listBox);

                    // ユーザの選択した値を取得する。
                    var selection = listBox.SelectedItem as EncodingInfo;
                    return selection == null ? null : selection.GetEncoding();
                }
            }
            else
            {
                return base.EditValue(context, provider, value);
            }
        }

        /// <summary><see cref="EditValue"/>メソッドで使用するエディタ スタイルを取得します。</summary>
        /// <param name="context">追加のコンテキスト情報を取得するために使用できる <see cref="ITypeDescriptorContext"/>。</param>
        /// <returns>メソッドで使用するエディタ スタイルを示す <see cref="UITypeEditorEditStyle"/> 値。</returns>
        public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
        {
            // The listbox is a drop down control.
            if (context != null && context.Instance != null)
            {
                return UITypeEditorEditStyle.DropDown;
            }
            return base.GetEditStyle(context);
        }
    }
}